package com.analysis.utils;

import com.analysis.entity.User;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 会话管理器
 * 管理用户登录状态和会话信息
 */
@Component
public class SessionManager {

    // 会话信息类
    private static class SessionInfo {
        private User user;
        private LocalDateTime createTime;
        private LocalDateTime lastAccessTime;

        public SessionInfo(User user) {
            this.user = user;
            this.createTime = LocalDateTime.now();
            this.lastAccessTime = LocalDateTime.now();
        }

        public User getUser() {
            return user;
        }

        public LocalDateTime getCreateTime() {
            return createTime;
        }

        public LocalDateTime getLastAccessTime() {
            return lastAccessTime;
        }

        public void updateLastAccessTime() {
            this.lastAccessTime = LocalDateTime.now();
        }

        public boolean isExpired(int expireDays) {
            return lastAccessTime.isBefore(LocalDateTime.now().minusDays(expireDays));
        }
    }

    // 存储用户会话信息：token -> SessionInfo
    private final Map<String, SessionInfo> sessions = new ConcurrentHashMap<>();

    // 存储用户token：userId -> token
    private final Map<Long, String> userTokens = new ConcurrentHashMap<>();

    // 会话过期时间（天）
    private static final int SESSION_EXPIRE_DAYS = 30;

    /**
     * 用户登录，创建会话
     */
    public String createSession(User user) {
        // 如果用户已经登录，先清除旧会话
        if (userTokens.containsKey(user.getId())) {
            String oldToken = userTokens.get(user.getId());
            sessions.remove(oldToken);
        }

        // 生成新的token
        String token = generateToken();

        // 存储会话信息
        SessionInfo sessionInfo = new SessionInfo(user);
        sessions.put(token, sessionInfo);
        userTokens.put(user.getId(), token);

        return token;
    }

    /**
     * 根据token获取用户信息
     */
    public User getUserByToken(String token) {
        SessionInfo sessionInfo = sessions.get(token);
        if (sessionInfo != null) {
            // 检查会话是否过期
            if (sessionInfo.isExpired(SESSION_EXPIRE_DAYS)) {
                // 会话过期，清除会话
                removeSession(token);
                return null;
            }
            // 更新最后访问时间
            sessionInfo.updateLastAccessTime();
            return sessionInfo.getUser();
        }
        return null;
    }

    /**
     * 根据用户ID获取token
     */
    public String getTokenByUserId(Long userId) {
        return userTokens.get(userId);
    }

    /**
     * 验证token是否有效
     */
    public boolean isValidToken(String token) {
        if (token == null) {
            return false;
        }
        SessionInfo sessionInfo = sessions.get(token);
        if (sessionInfo != null) {
            // 检查会话是否过期
            if (sessionInfo.isExpired(SESSION_EXPIRE_DAYS)) {
                // 会话过期，清除会话
                removeSession(token);
                return false;
            }
            // 更新最后访问时间
            sessionInfo.updateLastAccessTime();
            return true;
        }
        return false;
    }

    /**
     * 用户登出，清除会话
     */
    public void removeSession(String token) {
        SessionInfo sessionInfo = sessions.get(token);
        if (sessionInfo != null) {
            User user = sessionInfo.getUser();
            sessions.remove(token);
            userTokens.remove(user.getId());
        }
    }

    /**
     * 根据用户ID登出
     */
    public void removeSessionByUserId(Long userId) {
        String token = userTokens.get(userId);
        if (token != null) {
            removeSession(token);
        }
    }

    /**
     * 清除所有会话
     */
    public void clearAllSessions() {
        sessions.clear();
        userTokens.clear();
    }

    /**
     * 获取当前在线用户数量
     */
    public int getOnlineUserCount() {
        return sessions.size();
    }

    /**
     * 生成token
     */
    private String generateToken() {
        return "token_" + UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 刷新token（延长会话时间）
     */
    public String refreshToken(String oldToken) {
        SessionInfo sessionInfo = sessions.get(oldToken);
        if (sessionInfo != null) {
            // 检查会话是否过期
            if (sessionInfo.isExpired(SESSION_EXPIRE_DAYS)) {
                // 会话过期，清除会话
                removeSession(oldToken);
                return null;
            }

            // 创建新token
            String newToken = generateToken();
            User user = sessionInfo.getUser();

            // 更新会话
            sessions.remove(oldToken);
            SessionInfo newSessionInfo = new SessionInfo(user);
            sessions.put(newToken, newSessionInfo);
            userTokens.put(user.getId(), newToken);

            return newToken;
        }
        return null;
    }

    /**
     * 定时清理过期会话
     * 每小时执行一次
     */
    @Scheduled(fixedRate = 3600000) // 1小时 = 3600000毫秒
    public void cleanExpiredSessions() {
        LocalDateTime now = LocalDateTime.now();
        int cleanedCount = 0;

        // 清理过期的会话
        sessions.entrySet().removeIf(entry -> {
            SessionInfo sessionInfo = entry.getValue();
            if (sessionInfo.isExpired(SESSION_EXPIRE_DAYS)) {
                // 同时清理用户token映射
                User user = sessionInfo.getUser();
                userTokens.remove(user.getId());
                return true;
            }
            return false;
        });

        System.out.println("会话清理完成，当前在线用户数: " + sessions.size());
    }

    /**
     * 获取会话统计信息
     */
    public String getSessionStats() {
        int totalSessions = sessions.size();
        int activeUsers = userTokens.size();

        StringBuilder stats = new StringBuilder();
        stats.append("会话统计信息:\n");
        stats.append("总会话数: ").append(totalSessions).append("\n");
        stats.append("活跃用户数: ").append(activeUsers).append("\n");
        stats.append("会话过期时间: ").append(SESSION_EXPIRE_DAYS).append("天\n");

        return stats.toString();
    }
}
